package cn.shengchao.examstar.me.course.ohs.local.appervices;

import cn.shengchao.examstar.me.collect.acl.ports.message.CourseDto;
import cn.shengchao.examstar.me.course.acl.ports.clients.IProductClient;
import cn.shengchao.examstar.me.course.acl.ports.repositories.IMyCourseRepository;
import cn.shengchao.examstar.me.course.domain.MyCourse;
import cn.shengchao.examstar.me.course.ohs.local.messages.Learning;
import cn.shengchao.examstar.me.play.acl.ports.repositories.IUserCoursePlayRepository;
import cn.shengchao.examstar.me.play.domain.UserCourse;
import cn.shengchao.examstar.product.acl.adapters.repositories.NodeKnowledgePointRepository;
import cn.shengchao.examstar.product.domain.entity.CourseKnowledgeNode;
import cn.shengchao.examstar.product.ohs.local.message.ProductDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.continew.starter.core.validation.CheckUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MyCourseAppService {

    @Autowired
    private IMyCourseRepository myCourseRepository;

    @Autowired
    private IProductClient iProductClient;

    @Autowired
    private IUserCoursePlayRepository iUserCoursePlayRepository;
    
    @Autowired
    private NodeKnowledgePointRepository nodeKnowledgePointRepository;

    public List<MyCourse> getMyCourseKnowledgeList(Long studentId, long courseId) {
        return myCourseRepository.getMyCourseKnowledgeList(studentId, courseId);
    }

    public void addCourse(String orderId, Long userId, Long courseId, List<Long> knowledgeNodeIds, Long unlockType) {
        log.info("添加课程:{},{},{},{}", orderId, userId, courseId, knowledgeNodeIds);
        myCourseRepository.addCourse(orderId, userId, courseId, knowledgeNodeIds, unlockType);
    }

    public List<Long> getList(Long uid) {
        return myCourseRepository.getMyCourseList(uid);
    }

    public List<Learning> learning(Long uid, String[] ids) {
        log.info("获取课程相信信息");
        List<CourseDto> courseDtoList = iProductClient.getProductList(Arrays.stream(ids).map(Long::valueOf).toList());
        log.info("获取我的看课记录");
        List<Learning> learnings = new ArrayList<>();
        List<CompletableFuture<Void>> futures = courseDtoList.stream()
                .map(courseDto -> CompletableFuture.runAsync(() -> {
                    Learning learning = new Learning();
                    List<MyCourse> myCourses = myCourseRepository.getMyCourseKnowledgeList(uid, courseDto.getId());
                    learning.setCourseId(courseDto.getId());
                    learning.setCourseName(courseDto.getName());
                    learning.setTeachers(courseDto.getTeacher());
                    learning.setImgUrl(courseDto.getImgUrl());
                    //知识点数量
                    learning.setSum(courseDto.getKnowledgeNodeNum());
                    if (!myCourses.isEmpty()) {
                        Optional<MyCourse> last = myCourses.stream()
                                .filter(myCourse -> myCourse.getLastPlayTime() != null)
                                .max(Comparator.comparing(MyCourse::getLastPlayTime));
                        MyCourse lastMyCourse = last.orElse(myCourses.getFirst());
                        learning.setKnowledgeNodeId(lastMyCourse.getKnowledgeNodeId());
                        //知识点名称
                        CourseKnowledgeNode courseKnowledgeNode = courseDto.getKnowledgeNodes()
                                .stream()
                                .filter(item -> item.getId().equals(learning.getKnowledgeNodeId()))
                                .findFirst()
                                .orElse(new CourseKnowledgeNode());
                        if (courseKnowledgeNode.getName() != null) {
                            learning.setKnowledgeNodeName(courseKnowledgeNode.getName().getValue());
                        }
                        //学习进度(总看课进度/总的课程时长)
                        double durationSum = courseDto.getKnowledgeNodes()
                                .stream()
                                .filter(item -> item.getIsLesson() == 1 && item.getDuration() != null)
                                .mapToDouble(CourseKnowledgeNode::getDuration)
                                .sum();
                        if (durationSum != 0) {
                            learning.setLearnProgress(myCourses.stream()
                                    .filter(item -> item.getWatchProgress() != null)
                                    .mapToDouble(MyCourse::getWatchProgress)
                                    .sum() / durationSum);
                        }
                    }
                    long completeSum = 0;
                    Map<Long, Optional<CourseKnowledgeNode>> map = courseDto.getKnowledgeNodes()
                            .stream()
                            .collect(Collectors.groupingBy(CourseKnowledgeNode::getId, Collectors.reducing((a, b) -> b)));
                    for (MyCourse myCourse : myCourses) {
                        Optional<CourseKnowledgeNode> courseKnowledgeNodeOptional = map.getOrDefault(myCourse
                                .getKnowledgeNodeId(), Optional.empty());
                        if (courseKnowledgeNodeOptional.isPresent() && myCourse.getWatchProgress() != null && courseKnowledgeNodeOptional
                                .get()
                                .getDuration() != null) {
                            double progress = Double.valueOf(myCourse.getWatchProgress()) / courseKnowledgeNodeOptional
                                    .get()
                                    .getDuration();
                            if (progress > 90) {
                                completeSum = completeSum + 1;
                            }
                        }
                    }
                    learning.setCompleteSum(completeSum);
                    learning.setUnlockSum((long) myCourses.size());
                    learnings.add(learning);
                }))
                .toList();
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        return learnings;
    }

    public Long getStudentSum(List<Long> courseIds) {
        return myCourseRepository.getStudentSum(courseIds);
    }

    public Long getMyUseFreeUnlockSum(Long id, Long userId) {
        return myCourseRepository.getMyUseFreeUnlockSum(id, userId);
    }

    public Long getFreeUnlockSum(Long id, Long userId) {
        Long sum = iProductClient.getFreeUnlockSum(id);
        if (sum == 0L) {
            return sum;
        }
        Long useSum = getMyUseFreeUnlockSum(id, userId);
        return sum - useSum;
    }

    @Transactional
    public void useFreeUnlockSum(Long courseId, Long courseNodeId, Long userId,String orderId) {
        ProductDto node = iProductClient.getProduct(courseNodeId);
        //折扣价0是免费不消耗免费解锁次数
        if (node.getDiscountPrice().doubleValue() == 0) {
            //直接发放课程，订单成功事件判断过滤了，那边解锁类型不一样。
            addCourse(orderId, userId, courseId, List.of(courseNodeId), 2L);
            return;
        }
        Long unlockSum = getFreeUnlockSum(courseId, userId);
        CheckUtils.throwIf(unlockSum == 0L, "没有可用的免费解锁次数");
        //保存解锁记录
        myCourseRepository.addUseFreeUnlockSumLog(courseId, courseNodeId, userId);
        //发放课程
        addCourse(orderId, userId, courseId, List.of(courseNodeId), 2L);
    }

    public void removeCourse(Long userId, Long productId, List<Long> productItemId) {
        myCourseRepository.removeCourse(userId, productId, productItemId);
    }

    /**
     * 学员解锁知识点数量
     */
    public Map<Long, Set<Long>> getMyCourseKnowledgeSum(Long userId) {
        return myCourseRepository.getMyCourseKnowledgeSum(userId);
    }

    public List<Long> getListByPlay(Long uid) {
        return iUserCoursePlayRepository.getMyCoursePalyList(uid);
    }

    /**
     * 检查用户是否解锁了指定的课程节点列表
     *
     * @param userId        用户ID
     * @param courseNodeIds 需要检查的课程节点ID列表
     * @return 已解锁的课程节点ID集合
     */
    public List<MyCourse> checkUserUnlockedCourseNodes(Long userId, List<Long> courseNodeIds) {
        return myCourseRepository.checkUserUnlockedCourseNodes(userId, courseNodeIds);
    }


    /**
     * 最近一次播放
     *
     * @param uid      用户id
     * @param courseId 课程id
     * @return
     */
    public MyCourse lastPlay(Long uid, String courseId) {
        UserCourse userCourse = iUserCoursePlayRepository.last(uid, courseId);
        if (userCourse == null) {
            return null;
        }
        MyCourse myCourse = new MyCourse();
        BeanUtils.copyProperties(userCourse, myCourse);
        myCourse.setPlayProgress(userCourse.getLastPlayProgress());
        return myCourse;
    }
}
